package com.sinosoft.util;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sinosoft.annotations.FieldName;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import javax.net.ssl.SSLContext;
import javax.persistence.Column;
import javax.persistence.Table;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.SocketTimeoutException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * @author ChangJianXiong
 * @date 2022/3/17
 */
@Slf4j
public class CommonUtil {

    private static String[] IGNORE_COLUMNS = {"id"};

    /**
     * 将传入的任何数组或集合转换为(...),(...)的格式,用于插入sql(insert) values 后的数据拼接
     * @param objs 传入的对象集合或对象数组
     * @param ignoreFieldNames 忽略的列,默认忽略自增主键id列
     * @return
     */
    public static String values(Object objs,String ... ignoreFieldNames){
        Assert.notNull(objs,"传入参数为空,请检查!");
        StringBuilder result = new StringBuilder();
        try{

            boolean array = false;
            boolean collection = false;

            //如果是数组,转为list
            if(objs instanceof Object[]){
                objs = Arrays.asList((Object[]) objs);
                array = true;
            }
            //如果是collection,获取collection中的每个对象,循环获取每个对象中的field,获取field对应的值,拼接为 -> values ('a',null),(null,'2022-02-13 13:33:12') <- 最终返回值
            if(objs instanceof Collection){
                collection = true;
            }
            if(!array && !collection){
                objs = Arrays.asList(objs);
            }
            Collection<?> objects = (Collection<?>) objs;
            result.append("values ");
            for (Object next : objects) {
                //每一个obj都是一个对象
                result.append("(");
                Class<?> objClass = next.getClass();
                Field[] declaredFields = objClass.getDeclaredFields();
                for (Field field : declaredFields) {
                    field.setAccessible(true);
                    if (ObjectUtils.isEmpty(ignoreFieldNames)) {
                        ignoreFieldNames = IGNORE_COLUMNS;
                    }
                    List<String> ignoreFieldNameList = Arrays.asList(ignoreFieldNames);
                    String name = field.getName();
                    if (ignoreFieldNameList.contains(name)) {
                        continue;
                    }
                    //值
                    Object value = field.get(next);
                    if(ObjectUtils.isEmpty(value)){
                        result.append("null");
                    }else{
                        if(value instanceof String){
                            if(((String) value).startsWith("'")){
                                result.append("''");
                            }else{
                                result.append("'");
                            }
                            result.append(value);
                            if(((String) value).endsWith("'")){
                                result.append("''");
                            }else{
                                result.append("'");
                            }
                        }else{
                            result.append("'").append(value).append("'");
                        }
                    }
                    result.append(",");
                }
                //此时的值类似('a','b','c'),('e','f','g',  最后多一个","
                if (result.toString().endsWith(",")) {
                    result = new StringBuilder(result.substring(0, result.length() - 1));
                }
                result.append("),");
            }
            //此时的值类似('a','b'),('c','d'),  最后多一个","
            if(result.toString().endsWith(",")){
                result = new StringBuilder(result.substring(0,result.length()-1));
            }
        }catch (Exception e){
            log.error("an exception happened in generateValues()",e);
        }
        return result.toString();
    }

    /**
     * 组成insert语句中的column
     * @param objs 操作的对象或对象数组或集合
     * @param ignoreColumns 忽略不操作的列(默认忽略自增id列)
     * @return
     */
    public static String insertPrefix(Object objs,String ... ignoreColumns){
        Assert.notNull(objs,"传入参数为空,请检查");
        Object obj = new Object();
        StringBuilder columnNames = new StringBuilder();

        boolean array = false;
        boolean collection = false;

        try{
            //如果是数组转换为list
            if(objs instanceof Object[]){
                objs = Arrays.asList((Object[]) objs);
                array = true;
            }
            //如果是colleciton的子类,获取其中的一个对象
            if(objs instanceof Collection){
                Collection<?> objects = (Collection<?>) objs;
                for (Object object : objects) {
                    obj = object;
                    collection = true;
                    break;
                }
            }
            if(!array && !collection){
                obj = objs;
            }
            //反射获取Class
            Class<?> objClass = obj.getClass();
            //获取这个类上的注解
            Annotation[] annotations = objClass.getDeclaredAnnotations();
            //如果类上有注解 Table 就可以获取表名,拼接为 insert into table (
            for (Annotation annotation : annotations) {
                if(annotation instanceof Table){
                    String tableName = ((Table) annotation).name();
                    columnNames.append("insert into ").append(tableName).append("(");
                }
            }
            //获取属性,获取每个属性上的Column注解,column注解中name就是字段名,同时忽略不插入的列,如id,然后拼接,得到 -> insert into table (column1,column2) <- 这也是这个方法的最终返回值
            Field[] fields = objClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();
                Annotation[] fieldDeclaredAnnotations = field.getDeclaredAnnotations();
                for (Annotation fieldDeclaredAnnotation : fieldDeclaredAnnotations) {
                    if(fieldDeclaredAnnotation instanceof Column){
                        String columnName = ((Column) fieldDeclaredAnnotation).name();
                        if(!StringUtils.equals(name, columnName)){
                            name = columnName;
                        }
                    }
                }
                //跳过忽略的列
                if(ObjectUtils.isEmpty(ignoreColumns)){
                    ignoreColumns = IGNORE_COLUMNS;
                }
                List<String> ignore = Arrays.asList(ignoreColumns);
                if(ignore.contains(name)){
                    continue;
                }
                columnNames.append(name).append(",");
            }
            if(columnNames.toString().endsWith(",")){
                columnNames = new StringBuilder(columnNames.substring(0,columnNames.length()-1));
            }
            columnNames.append(") ");
        }catch (Exception e){
            log.error("an exception was happened in generateColumnNameStr()");
        }
        return columnNames.toString();
    }

    /**
     * 复制属性值(不支持深度复制,如复制对象中存在自定义的对象)
     * 将传入的r对象上的属性值复制到t对象上
     * 如果属性名称一致(忽略大小写),可以直接复制
     * 如果属性名称不一致,需要使用@FieldName(name="r对象中属性名称")来标记才可进行复制
     * 注意:如果是 @see java.util.Date 类型的子类,请直接保持子类类型相同
     * @see org.springframework.beans.BeanUtils
     * @param r 传入的源对象
     * @param t 接收属性值的对象
     * @param <T> 接收对象类型
     * @param <R> 源对象类型
     * @return
     */
    public static <T,R> T copyProperties(R r, T t,String ... ignoreColumns){
        Assert.notNull(r,"参数不能为空");
        Assert.notNull(t,"参数不能为空");
        try{
            Class<?> tClass = t.getClass();
            Class<?> rClass = r.getClass();

            Map<String,Object> fieldNameValues = new HashMap<>();
            Field[] rClassDeclaredFields = rClass.getDeclaredFields();
            for (Field declaredField : rClassDeclaredFields) {
                declaredField.setAccessible(true);
                String name = declaredField.getName();
                name = name.toLowerCase();
                Object value = declaredField.get(r);
                fieldNameValues.put(name,value);
            }
            if(ObjectUtils.isEmpty(ignoreColumns)){
                ignoreColumns = IGNORE_COLUMNS;
            }
            List<String> ignoreColumnList = Arrays.asList(ignoreColumns);
            Field[] tClassDeclaredFields = tClass.getDeclaredFields();
            for (Field tClassDeclaredField : tClassDeclaredFields) {
                tClassDeclaredField.setAccessible(true);
                String name = tClassDeclaredField.getName();
                if(ignoreColumnList.contains(name)){
                    continue;
                }
                String lowerCaseName = name.toLowerCase();
                if (fieldNameValues.containsKey(lowerCaseName)) {
                    Object rClassFieldValue = fieldNameValues.get(lowerCaseName);
                    if(ObjectUtils.isEmpty(rClassFieldValue)){
                        continue;
                    }
                    tClassDeclaredField.set(t,rClassFieldValue);
                }else{
                    Annotation[] declaredAnnotations = tClassDeclaredField.getDeclaredAnnotations();
                    for (Annotation annotation : declaredAnnotations) {
                        if(annotation instanceof FieldName){
                            String[] annotationValues = ((FieldName) annotation).name();
                            for (String annotationValue : annotationValues) {
                                if(ignoreColumnList.contains(annotationValue)){
                                    continue;
                                }
                                annotationValue = annotationValue.toLowerCase();
                                if (fieldNameValues.containsKey(annotationValue)) {
                                    Object rClassFieldValue = fieldNameValues.get(annotationValue);
                                    if(ObjectUtils.isEmpty(rClassFieldValue)){
                                        continue;
                                    }
                                    tClassDeclaredField.set(t,rClassFieldValue);
                                }
                            }
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("an exception happened in copyProperties()",e);
        }
        return t;
    }
    public static <T,R> T copyProperties(R r, T t){
        return copyProperties(r, t, IGNORE_COLUMNS);
    }
    /**
     * java生成随机数字和字母组合
     * @param length 生成随机数的长度
     * @return
     */
    public static String getCharAndNumr(int length) {
        String val = "";
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            // 输出字母还是数字
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            // 字符串
            if ("char".equalsIgnoreCase(charOrNum)) {
                // 取得大写字母还是小写字母
                int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val += (char) (choice + random.nextInt(26));
            } else if ("num".equalsIgnoreCase(charOrNum)) { // 数字
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val;
    }


}
